#ifndef _WIN32
# include <unistd.h> // close
# define closesocket(x) close(x)
#else
#  pragma comment(lib, "ws2_32.lib")
#endif

#include "socket.h"

eSocket::eSocket ( int             handle,
                   eSocketAddress  addr,
                   eSocketDomain   domain,
                   eSocketType     type,
                   eSocketProtocol protocol )
{
  handle_   = handle;
  address_  = addr;
  domain_   = domain;
  type_     = type;
  protocol_ = protocol;
}

eSocket::~eSocket (void)
{
  close ();
}

#include <cstdio>

bool
eSocket::bind (eSocketAddress addr)
{
  int ret = ::bind (handle_, (sockaddr *)&addr.address, addr.size);

  if (getErrorCode (ret) == 0) {
    address_ = addr;
    return true;
  }

  return false;
}

bool
eSocket::connect (eSocketAddress addr)
{
  int ret = ::connect (handle_, (sockaddr *)&addr.address, addr.size);

  if (getErrorCode (ret) == 0) {
    address_ = addr;
    return true;
  }

  return false;
}

bool
eSocket::close (void)
{
  if (handle_ != -1) {
#ifndef _WIN32
    shutdown (handle_, SHUT_RDWR);
#else
    shutdown (handle_, SD_BOTH);
#endif

    if (closesocket (handle_) == 0) {
      handle_ = -1;
      return true;
    }

    return false;
  }

  /* Was not open to begin with... */
  return true;
}

ssize_t
eSocket::recv (void* buffer, size_t length)
{
  return ::recv (handle_, (char *)buffer, length, 0);//MSG_WAITALL);
}

ssize_t
eSocket::send (const void* data, size_t length)
{
  return ::send (handle_, (const char *)data, length, 0);
}

int
eSocket::getErrorCode (int ret_code)
{
/* WinSock requires a separate function call to determine errors. */
#ifdef _WIN32
  return WSAGetLastError ();
#else
  /* Most BSD socket implementations return the error code... */
  return ret_code;
#endif
}

void
eSocketAddress::setAddress (const char* szHost)
{
  if (*szHost == '*') {
    setAddressAny ();
    return;
  }

  struct hostent* remote_host;

  remote_host = gethostbyname (szHost);

  if (remote_host != NULL) {
#ifdef WIN32
    address.sin_addr.s_addr = *(u_long *) remote_host->h_addr_list [0];
#else
    address.sin_addr = *(u_long *) remote_host->h_addr_list [0];
#endif
    ////printf("\tIP Address #%d: %s\n", i, inet_ntoa (address.sin_addr));
  } else {
#ifndef WIN32
    inet_aton ((char *)szHost, &address.sin_addr);
#else
    address.sin_addr.s_addr = inet_addr (szHost);
#endif
  }
}